#pragma once

namespace good_cptl
{
namespace hash_function
{

/*
这个函数是一个哈希函数，用于将128位输入（由两个64位整数表示）压缩为64位输出
这个哈希函数的设计灵感来自Murmur哈希算法。它通过多次使用异或、位移和乘法操作来充分混合输入的位，以产生均匀分布的哈希值。这种方法有助于减少哈希冲突，并在各种应用场景中提供良好的性能。
这个函数特别适用于需要将128位数据（如两个64位整数的组合）快速哈希为64位值的场景
*/
constexpr uint64_t hash_128_to_64(
    const uint64_t upper, const uint64_t lower) noexcept
{
  // Murmur-inspired hashing.
  const uint64_t kMul = 0x9ddfea08eb382d69ULL;
  uint64_t a = (lower ^ upper) * kMul;
  a ^= (a >> 47);
  uint64_t b = (upper ^ a) * kMul;
  b ^= (b >> 47);
  b *= kMul;
  return b;
}


/*
这个函数是一个交换性哈希函数，它接受两个64位无符号整数作为输入，并生成一个64位哈希值。
这个函数保证 hash(a,b) = hash(b, a)
*/
constexpr uint64_t commutative_hash_128_to_64(
    const uint64_t upper, const uint64_t lower) noexcept
{
  return 3860031 + (upper + lower) * 2779 + (upper * lower * 2);
}

/*
Thomas Wang的64位混合哈希函数的实现。
这个函数的目的是通过一系列位操作来充分混合输入值的位，产生一个看似随机但实际上是确定性的输出。
这种混合函数在哈希表实现、随机数生成等场景中非常有用，因为它能够将输入空间均匀地映射到输出空间，
减少哈希冲突的可能性。
*/
constexpr uint64_t twang_mix64(uint64_t key) noexcept
{
  key = (~key) + (key << 21); // key *= (1 << 21) - 1; key -= 1;
  key = key ^ (key >> 24);
  key = key + (key << 3) + (key << 8); // key *= 1 + (1 << 3) + (1 << 8)
  key = key ^ (key >> 14);
  key = key + (key << 2) + (key << 4); // key *= 1 + (1 << 2) + (1 << 4)
  key = key ^ (key >> 28);
  key = key + (key << 31); // key *= 1 + (1 << 31)
  return key;
}

/*
这个twang_unmix64函数是twang_mix64函数的逆函数。
*/
constexpr uint64_t twang_unmix64(uint64_t key) noexcept
{
  // See the comments in jenkins_rev_unmix32 for an explanation as to how this
  // was generated
  key *= 4611686016279904257U;
  key ^= (key >> 28) ^ (key >> 56);
  key *= 14933078535860113213U;
  key ^= (key >> 14) ^ (key >> 28) ^ (key >> 42) ^ (key >> 56);
  key *= 15244667743933553977U;
  key ^= (key >> 24) ^ (key >> 48);
  key = (key + 1) * 9223367638806167551U;
  return key;
}

/*
Robert Jenkins的可逆32位混合哈希函数
*/
constexpr uint32_t jenkins_rev_mix32(uint32_t key) noexcept
{
  key += (key << 12); // key *= (1 + (1 << 12))
  key ^= (key >> 22);
  key += (key << 4); // key *= (1 + (1 << 4))
  key ^= (key >> 9);
  key += (key << 10); // key *= (1 + (1 << 10))
  key ^= (key >> 2);
  // key *= (1 + (1 << 7)) * (1 + (1 << 12))
  key += (key << 7);
  key += (key << 12);
  return key;
}

/*
这个函数是jenkins_rev_mix32的逆函数
*/
constexpr uint32_t jenkins_rev_unmix32(uint32_t key) noexcept
{
  // These are the modular multiplicative inverses (in Z_2^32) of the
  // multiplication factors in jenkins_rev_mix32, in reverse order.  They were
  // computed using the Extended Euclidean algorithm, see
  // http://en.wikipedia.org/wiki/Modular_multiplicative_inverse
  key *= 2364026753U;

  // The inverse of a ^= (a >> n) is
  // b = a
  // for (int i = n; i < 32; i += n) {
  //   b ^= (a >> i);
  // }
  key ^= (key >> 2) ^ (key >> 4) ^ (key >> 6) ^ (key >> 8) ^ (key >> 10) ^
      (key >> 12) ^ (key >> 14) ^ (key >> 16) ^ (key >> 18) ^ (key >> 20) ^
      (key >> 22) ^ (key >> 24) ^ (key >> 26) ^ (key >> 28) ^ (key >> 30);
  key *= 3222273025U;
  key ^= (key >> 9) ^ (key >> 18) ^ (key >> 27);
  key *= 4042322161U;
  key ^= (key >> 22);
  key *= 16773121U;
  return key;
}

//  fnv
//
//  Fowler / Noll / Vo (FNV) Hash
//    http://www.isthe.com/chongo/tech/comp/fnv/
//
//  Discouraged for poor performance in the smhasher suite.

constexpr uint32_t fnv32_hash_start = 2166136261UL;
constexpr uint64_t fnv64_hash_start = 14695981039346656037ULL;
constexpr uint64_t fnva64_hash_start = 14695981039346656037ULL;


/*
这个函数提供了一种高效的方式来将单个字节整合到现有的FNV哈希值中，是实现FNV哈希算法的关键组成部分
*/
constexpr uint32_t fnv32_append_byte(uint32_t hash, uint8_t c)
{
  hash = hash //
      + (hash << 1) //
      + (hash << 4) //
      + (hash << 7) //
      + (hash << 8) //
      + (hash << 24);
  // forcing signed char, since other platforms can use unsigned
  hash ^= static_cast<int8_t>(c);
  return hash;
}




}
}